package com.Java.train.business.service.Impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.Java.train.business.entity.ConfirmOrder;
import com.Java.train.business.entity.DTO.ConfirmOrderReqDTO;
import com.Java.train.business.entity.DailyTrainTicket;
import com.Java.train.business.entity.Train;
import com.Java.train.business.enums.ConfirmOrderStatusEnum;
import com.Java.train.business.enums.RabbitQueueEnums;
import com.Java.train.business.mapper.ConfirmOrderMapper;
import com.Java.train.business.req.ConfirmOrderDoReq;
import com.Java.train.business.service.ConfirmOrderService;
import com.Java.train.business.service.TrainService;
import com.Java.train.business.service.daily.DailyTrainTicketService;
import com.Java.train.common.context.LoginMemberContext;
import com.Java.train.common.exception.BusniessException;
import com.Java.train.common.exception.BusniessExceptionEnum;
import com.Java.train.common.utils.SnowFlakeUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import jakarta.annotation.Resource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.Date;


@Service
public class BeforeConfirmOrderService {
    private static final Logger LOG = LoggerFactory.getLogger(BeforeConfirmOrderService.class);
    @Resource
    StringRedisTemplate stringRedisTemplate;
    @Resource
    RabbitTemplate rabbitTemplate;
    @Resource
    SkTokenServiceImpl skTokenService;
    @Resource
    ConfirmOrderMapper confirmOrderMapper;
    @Resource
    TrainService trainService;
    @Resource
    DailyTrainTicketService dailyTrainTicketService;

    @Value("${spring.profiles.active}")
    private String env;

    public Long beforeDoConfirm(ConfirmOrderDoReq confirmOrderDoReq){
        // 1. 验证图形验证码
        if(!env.equals("dev")) {
            String userImageCode = confirmOrderDoReq.getImageCode();
            String imageCodeToken = confirmOrderDoReq.getImageCodeToken();
            String realImageCode = stringRedisTemplate.opsForValue().get(imageCodeToken);
            if (StrUtil.isBlank(realImageCode)) {
                throw new BusniessException(BusniessExceptionEnum.IMAGE_CODE_PASS_AWAY);
            }
            if (!realImageCode.equalsIgnoreCase(userImageCode)) {
                // 验证码不对
                LOG.info("验证码错误了老弟");
                throw new BusniessException(BusniessExceptionEnum.IMAGE_CODE_WRONG);
            } else {
                stringRedisTemplate.delete(imageCodeToken);
            }
        }

        // 校验是否存在该列车等信息
        // 2.1 校验该车次是否存在
        Date date = confirmOrderDoReq.getDate();
        String trainCode = confirmOrderDoReq.getTrainCode();
        Train train = trainService.getOne(new LambdaQueryWrapper<Train>().eq(Train::getCode, trainCode));
//        if(ObjectUtil.isEmpty(train)){
//            throw new BusniessException(BusniessExceptionEnum.BUSINESS_TRAIN_NOT_EXITS);
//        }
//        // 2.3 校验该余票是否存在
//        LOG.info("日期为：{}", date);
//        String start = confirmOrderDoReq.getStart();
//        String end = confirmOrderDoReq.getEnd();
//        // 通过唯一键查找票
//        DailyTrainTicket ticket = dailyTrainTicketService.getOne(new LambdaQueryWrapper<DailyTrainTicket>().eq(DailyTrainTicket::getTrainCode, trainCode)
//                .eq(DailyTrainTicket::getDate, date).eq(DailyTrainTicket::getStart, start).eq(DailyTrainTicket::getEnd, end));
//        LOG.info("查出的唯一车票为：{}", ticket);
//        if(ObjectUtil.isEmpty(ticket)){
//            throw new BusniessException(BusniessExceptionEnum.BUSINESS_TICKET_NOT_EXITS);
//        }

        // 3.获取令牌
        // 分布式获取令牌，只有有令牌才能进行购票，并给出限制购票运行令牌的时间，防止同一人短时间大量抢票，手动限流（限个人）
        boolean vaildSkToken = skTokenService.vaildSkToken(date, trainCode);
        if(vaildSkToken == false){
            // 没令牌了
            throw new BusniessException(BusniessExceptionEnum.TICKET_TOKEN_ALREADY_EXITS);
        }

        // 4.初始化订单信息，及时给予用户信息反馈
        DateTime now = DateTime.now();
        ConfirmOrder confirmOrder = new ConfirmOrder();
        confirmOrder.setId(SnowFlakeUtil.getSnowFlakeNextId());
        confirmOrder.setMemberId(LoginMemberContext.getId());
        confirmOrder.setDate(date);
        confirmOrder.setTrainCode(trainCode);
        confirmOrder.setStart(confirmOrderDoReq.getStart());
        confirmOrder.setEnd(confirmOrderDoReq.getEnd());
        confirmOrder.setDailyTrainTicketId(confirmOrderDoReq.getDailyTrainTicketId());
        confirmOrder.setTickets(JSON.toJSONString(confirmOrderDoReq.getTickets()));
        confirmOrder.setStatus(ConfirmOrderStatusEnum.INIT.getCode());
        confirmOrder.setCreateTime(now);
        confirmOrder.setUpdateTime(now);
        LOG.info("订单信息如下：{}", confirmOrder);
        confirmOrderMapper.insert(confirmOrder);

        // 5.将当前订单所需信息封装为DTO，并存入消息队列中
        ConfirmOrderReqDTO confirmOrderReqDTO = BeanUtil.copyProperties(confirmOrderDoReq, ConfirmOrderReqDTO.class);
        confirmOrderReqDTO.setLogId(MDC.get("LOG_ID"));
        confirmOrderReqDTO.setMemberId(LoginMemberContext.getId());
        LOG.info("向消息队列中传入信息");
        String message = JSON.toJSONString(confirmOrderReqDTO);
        LOG.info("传入消息为：{}", message);
        rabbitTemplate.convertAndSend("ConfirmOrder.queue", message);
        LOG.info("已向队列中添加订单消息");

        return confirmOrder.getId();
    }
}
